package ast

import (
	"showen7/ast"
	"showen7/tok"
	"testing"
)

func TestBooleanExpString(t *testing.T) {
	tests := []struct {
		name     string
		token    tok.Token
		expected string
	}{
		{
			name:     "true boolean",
			token:    tok.Token{Type: tok.BOOLEAN, Lexeme: "#t"},
			expected: "#t",
		},
		{
			name:     "false boolean",
			token:    tok.Token{Type: tok.BOOLEAN, Lexeme: "#f"},
			expected: "#f",
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			booleanExp := &ast.BooleanExp{Token: tt.token}
			if got := booleanExp.String(); got != tt.expected {
				t.Errorf("BooleanExp.String() = %v, want %v", got, tt.expected)
			}
		})
	}
}

func TestIdentifierExpString(t *testing.T) {
	tests := []struct {
		name     string
		token    tok.Token
		expected string
	}{
		{
			name:     "simple identifier",
			token:    tok.Token{Type: tok.IDENTIFIER, Lexeme: "x"},
			expected: "x",
		},
		{
			name:     "complex identifier",
			token:    tok.Token{Type: tok.IDENTIFIER, Lexeme: "define"},
			expected: "define",
		},
		{
			name:     "chinese identifier",
			token:    tok.Token{Type: tok.IDENTIFIER, Lexeme: "定义"},
			expected: "定义",
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			identifierExp := &ast.IdentifierExp{Token: tt.token}
			if got := identifierExp.String(); got != tt.expected {
				t.Errorf("IdentifierExp.String() = %v, want %v", got, tt.expected)
			}
		})
	}
}

func TestListExpString(t *testing.T) {
	tests := []struct {
		name     string
		exps     []ast.Exp
		expected string
	}{
		{
			name:     "empty list",
			exps:     []ast.Exp{},
			expected: "()",
		},
		{
			name: "list with one element",
			exps: []ast.Exp{
				&ast.IdentifierExp{Token: tok.Token{Type: tok.IDENTIFIER, Lexeme: "x"}},
			},
			expected: "(x)",
		},
		{
			name: "list with multiple elements",
			exps: []ast.Exp{
				&ast.IdentifierExp{Token: tok.Token{Type: tok.IDENTIFIER, Lexeme: "define"}},
				&ast.IdentifierExp{Token: tok.Token{Type: tok.IDENTIFIER, Lexeme: "x"}},
				&ast.IdentifierExp{Token: tok.Token{Type: tok.INTEGER, Lexeme: "1"}},
			},
			expected: "(define x 1)",
		},
		{
			name: "nested list",
			exps: []ast.Exp{
				&ast.IdentifierExp{Token: tok.Token{Type: tok.IDENTIFIER, Lexeme: "define"}},
				&ast.IdentifierExp{Token: tok.Token{Type: tok.IDENTIFIER, Lexeme: "add"}},
				&ast.ListExp{
					Exps: []ast.Exp{
						&ast.IdentifierExp{Token: tok.Token{Type: tok.IDENTIFIER, Lexeme: "lambda"}},
						&ast.ListExp{
							Exps: []ast.Exp{
								&ast.IdentifierExp{Token: tok.Token{Type: tok.IDENTIFIER, Lexeme: "x"}},
								&ast.IdentifierExp{Token: tok.Token{Type: tok.IDENTIFIER, Lexeme: "y"}},
							},
						},
						&ast.ListExp{
							Exps: []ast.Exp{
								&ast.IdentifierExp{Token: tok.Token{Type: tok.IDENTIFIER, Lexeme: "+"}},
								&ast.IdentifierExp{Token: tok.Token{Type: tok.IDENTIFIER, Lexeme: "x"}},
								&ast.IdentifierExp{Token: tok.Token{Type: tok.IDENTIFIER, Lexeme: "y"}},
							},
						},
					},
				},
			},
			expected: "(define add (lambda (x y) (+ x y)))",
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			listExp := &ast.ListExp{Exps: tt.exps}
			if got := listExp.String(); got != tt.expected {
				t.Errorf("ListExp.String() = %v, want %v", got, tt.expected)
			}
		})
	}
}
